import { ConfigPreview } from "@/docs/components/Preview";
import { Callout } from "nextra/components";

# Array

Render a list of items with a subset of fields. Extends [Base](base).

<ConfigPreview
  label="Example"
  componentConfig={{
    fields: {
      items: {
        type: "array",
        arrayFields: {
          title: { type: "text" },
        },
      },
    },
    defaultProps: { items: [{ title: "Apple" }, { title: "Banana" }] },
    render: ({ items }) => {
      return (
        <ul>
          {items.map((item, i) => (
            <li key={i}>{item.title}</li>
          ))}
        </ul>
      );
    },
  }}
/>

```tsx {5-10} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
          },
        },
      },
      render: ({ items }) => {
        return (
          <ul>
            {items.map((item, i) => (
              <li key={i}>{item.title}</li>
            ))}
          </ul>
        );
      },
    },
  },
};
```

## Params

| Param                                           | Example                                       | Type               | Status   |
| ----------------------------------------------- | --------------------------------------------- | ------------------ | -------- |
| [`type`](#type)                                 | `type: "array"`                               | "array"            | Required |
| [`arrayFields`](#arrayfields)                   | `arrayFields: { title: { type: "text" } }`    | Object             | Required |
| [`defaultItemProps`](#defaultitemprops)         | `defaultItemProps: { title: "Hello, world" }` | Object \| Function | -        |
| [`getItemSummary()`](#getitemsummaryitem-index) | `getItemSummary: (item) => item.title`        | Function           | -        |
| [`max`](#max)                                   | `max: 3`                                      | Number             | -        |
| [`min`](#min)                                   | `min: 1`                                      | Number             | -        |

## Required params

### `type`

The type of the field. Must be `"array"` for Array fields.

```tsx {6} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
          },
        },
      },
      // ...
    },
  },
};
```

### `arrayFields`

Describe the fields for each item in the array. Shares an API with `fields`.

Can include any field type, including nested array fields.

```tsx {7-9} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
          },
        },
      },
      // ...
    },
  },
};
```

## Optional params

### `defaultItemProps`

Set the default values when a new item is added to the array. Can be an object or a function that receives the current array index.

```tsx {10-12} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
          },
          defaultItemProps: {
            title: "Hello, world",
          },
        },
      },
      // ...
    },
  },
};
```

<ConfigPreview
  label="Example"
  componentConfig={{
    fields: {
      items: {
        type: "array",
        arrayFields: {
          title: { type: "text" },
        },
        defaultItemProps: {
          title: "Hello, world",
        },
      },
    },
    defaultProps: { items: [{ title: "Apple" }, { title: "Banana" }] },
    render: ({ items }) => {
      return (
        <ul>
          {items.map((item, i) => (
            <li key={i}>{item.title}</li>
          ))}
        </ul>
      );
    },
  }}
/>

You can also use a function to generate dynamic defaults:

```tsx {10-14} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
            order: { type: "number" },
          },
          defaultItemProps: (index) => ({
            title: `Item ${index + 1}`,
            order: index + 1,
          }),
        },
      },
      // ...
    },
  },
};
```

<ConfigPreview
  label="Dynamic Example"
  componentConfig={{
    fields: {
      items: {
        type: "array",
        arrayFields: {
          title: { type: "text" },
          order: { type: "number" },
        },
        defaultItemProps: (index) => ({
          title: `Item ${index + 1}`,
          order: index + 1,
        }),
      },
    },
    defaultProps: { items: [] },
    render: ({ items }) => {
      return (
        <ul>
          {items.map((item, i) => (
            <li key={i}>
              {item.title} (Order: {item.order})
            </li>
          ))}
        </ul>
      );
    },
  }}
/>

### `getItemSummary(item, index)`

Get a label of each item in the array. Returns a [ReactNode](https://react.dev/learn/typescript#typing-children).

<Callout type="warning">
  Avoid using interactive HTML elements like `<button>`, `<input>`, or `<a>` inside `getItemSummary`. These elements can interfere with the array field's built-in interactions (such as drag-and-drop reordering and item expansion). Stick to non-interactive elements like `<div>`, `<span>`, `<p>`, or plain text for summaries.
</Callout>

```tsx {10} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
          },
          getItemSummary: (item) => item.title || "Item",
        },
      },
      // ...
    },
  },
};
```

<ConfigPreview
  label="Example"
  componentConfig={{
    fields: {
      items: {
        type: "array",
        arrayFields: {
          title: { type: "text" },
        },
        getItemSummary: (item) => item.title || "Item",
      },
    },
    defaultProps: { items: [{ title: "Apple" }, { title: "Banana" }] },
    render: ({ items }) => {
      return (
        <ul>
          {items.map((item, i) => (
            <li key={i}>{item.title}</li>
          ))}
        </ul>
      );
    },
  }}
/>

### `max`

The maximum amount of items allowed in the array.

```tsx {10-10} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
          },
          max: 3,
        },
      },
      // ...
    },
  },
};
```

<ConfigPreview
  label="Example"
  componentConfig={{
    fields: {
      items: {
        type: "array",
        max: 3,
        arrayFields: {
          title: { type: "text" },
        },
      },
    },
    defaultProps: { items: [{ title: "Apple" }, { title: "Banana" }] },
    render: ({ items }) => {
      return (
        <ul>
          {items.map((item, i) => (
            <li key={i}>{item.title}</li>
          ))}
        </ul>
      );
    },
  }}
/>

### `min`

The minimum amount of items allowed in the array.

```tsx {10-10} copy
const config = {
  components: {
    Example: {
      fields: {
        items: {
          type: "array",
          arrayFields: {
            title: { type: "text" },
          },
          min: 1,
        },
      },
      // ...
    },
  },
};
```

<ConfigPreview
  label="Example"
  componentConfig={{
    fields: {
      items: {
        type: "array",
        min: 1,
        arrayFields: {
          title: { type: "text" },
        },
      },
    },
    defaultProps: { items: [{ title: "Apple" }, { title: "Banana" }] },
    render: ({ items }) => {
      return (
        <ul>
          {items.map((item, i) => (
            <li key={i}>{item.title}</li>
          ))}
        </ul>
      );
    },
  }}
/>
